package com.jintian.hnsj_metting.util;

import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.util.Printer;

import com.hikvision.smarteyes.utils.log.DFLog;

/**
 * @author dengjifu
 * 监控主线程hangler方法耗时的工具类
 */
public final class LogMonitor {

    private static final String TAG = "LogMonitor";

    private static LogMonitor sInstance = new LogMonitor();

    private Handler mIoHandler;
    //方法耗时阈值
    private static long TIME_BLOCK = 1500L;
    //方法调用链数
    private static long METHOD_STATCK_LENGTH = 20;

    private boolean started;

    /**
     * 开始监控
     */
    public void start(){

        if(started){
            return;
        }

        started = true;

        /**
         * 自定义打印日志类
         */
        Looper.getMainLooper().setMessageLogging(new Printer() {
            //分发和处理消息开始前的log
            private static final String START = ">>>>> Dispatching";
            //分发和处理消息结束后的log
            private static final String END = "<<<<< Finished";

            @Override
            public void println(String x) {
                if (x.startsWith(START)) {
                    //开始计时
                    startMonitor();
                }
                if (x.startsWith(END)) {
                    //结束计时，并计算出方法执行时间
                    removeMonitor();
                }
            }
        });
    }

    private LogMonitor() {
        HandlerThread logThread = new HandlerThread("log-time");
        logThread.start();
        mIoHandler = new Handler(logThread.getLooper());
    }

    private static Runnable mLogRunnable = new Runnable() {
        @Override
        public void run() {
            //打印出执行的耗时方法的栈消息
            StringBuilder sb = new StringBuilder();
            sb.append("\nStackTrace method call use time more than [").append(TIME_BLOCK).append("ms] in main thread !!! \n");
            StackTraceElement[] stackTrace = Looper.getMainLooper().getThread().getStackTrace();
            if(stackTrace == null){
                return;
            }

            if(stackTrace.length > METHOD_STATCK_LENGTH){
                for(int i=0;i<METHOD_STATCK_LENGTH;i++){
                    sb.append(stackTrace[i].toString());
                    sb.append("\n");
                }
                sb.append("...");
            }else {
                for (StackTraceElement s : stackTrace) {
                    sb.append(s.toString());
                    sb.append("\n");
                }
            }
            DFLog.e(TAG,sb.toString()+"\n\n");
        }
    };

    public static LogMonitor getInstance() {
        return sInstance;
    }

    /**
     * 开始计时
     */
    private void startMonitor() {
        mIoHandler.postDelayed(mLogRunnable, TIME_BLOCK);
    }

    /**
     * 停止计时
     */
    private void removeMonitor() {
        mIoHandler.removeCallbacks(mLogRunnable);
    }

    /**
     * 设置log打印的调用栈数
     * 避免循环调用或调用栈过长时
     * 打印无效循环日志消耗资源
     * @param methodStatckLength
     */
    public void setMethodStatckLength(long methodStatckLength) {
        if(methodStatckLength > 0){
            METHOD_STATCK_LENGTH = methodStatckLength;
        }
    }

    /**
     * 设置方法调用超时监控的阈值
     * @param timeBlock 默认1500ms
     */
    public void setTimeBlock(long timeBlock) {
        if(timeBlock >= 300){
            TIME_BLOCK = timeBlock;
        }
    }
}
